package com.ruoyi.system.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.PageHelper;
import com.ruoyi.common.enums.EmployeeTypeEnum;
import com.ruoyi.common.utils.AutoCreateNumberUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.EmployeeRoleReleation;
import com.ruoyi.system.domain.biz.EmployeeVo;
import com.ruoyi.system.domain.biz.RoleDetail;
import com.ruoyi.system.domain.dto.EmployeeAndReleationDto;
import com.ruoyi.system.domain.dto.EmployeeDto;
import com.ruoyi.system.domain.vo.EmployQueryVo;
import com.ruoyi.system.domain.vo.RoleRegisterVo;
import com.ruoyi.system.execute.DictCacheManager;
import com.ruoyi.system.mapper.EmployeeRoleReleationMapper;
import com.ruoyi.system.service.CommonOpenApiService;
import com.ruoyi.system.wx.login.WxLoginService;
import com.ruoyi.system.wx.login.domain.WxLoginVo;
import com.ruoyi.system.wx.login.domain.WxUserDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.EmployeeMapper;
import com.ruoyi.system.domain.Employee;
import com.ruoyi.system.service.IEmployeeService;
import org.springframework.util.Assert;

import javax.annotation.PostConstruct;

import static com.ruoyi.common.constant.Constants.label;
import static com.ruoyi.common.constant.Constants.value;
import static com.ruoyi.system.execute.DictCacheManager.DICT_CACHE;
import static com.ruoyi.system.service.impl.CommonOpenApiServiceImpl.USER_USER_PREFIX;

/**
 * 【请填写功能名称】Service业务层处理
 *
 * @author ruoyi
 * @date 2024 -11-29
 */
@Service
@Slf4j
public class EmployeeServiceImpl implements IEmployeeService {
    @Autowired
    private EmployeeMapper employeeMapper;

    @Autowired
    private DictCacheManager dictCacheManager;

    @Autowired
    private EmployeeRoleReleationMapper employeeRoleReleationMapper;

    @Autowired
    private CommonOpenApiService commonOpenApiService;

    public static final String JDDZCODE = "jddzcode";

    @Value("${dict.employee.hg}")
    private String hgDicSplit;

    private static final Map<String, Map<String, Integer>> EMPLOYEE_DICT = new HashMap<>();


    @PostConstruct
    private void load() {
        if (!StringUtils.isEmpty(hgDicSplit)) {
            Map<String, Integer> map = new HashMap<>();
            EMPLOYEE_DICT.put(EmployeeTypeEnum.hg.name(), map);
            Arrays.stream(hgDicSplit.split(",")).forEach(x -> map.put(x, 1));
        }
    }

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 查询【请填写功能名称】
     *
     * @param id 【请填写功能名称】主键
     * @return 【请填写功能名称】
     */
    @Override
    public Employee selectEmployeeById(Long id) {
        return employeeMapper.selectEmployeeById(id);
    }

    /**
     * 查询【请填写功能名称】列表
     *
     * @param employee 【请填写功能名称】
     * @return 【请填写功能名称】
     */
    @Override
    public List<Employee> selectEmployeeList(Employee employee) {
        return employeeMapper.selectEmployeeList(employee);
    }

    /**
     * 新增【请填写功能名称】
     *
     * @param employee 【请填写功能名称】
     * @return 结果
     */
    @Override
    public int insertEmployee(Employee employee) {
        return employeeMapper.insertEmployee(employee);
    }

    /**
     * 修改【请填写功能名称】
     *
     * @param employee 【请填写功能名称】
     * @return 结果
     */
    @Override
    public int updateEmployee(Employee employee) {
        return employeeMapper.updateEmployee(employee);
    }

    /**
     * 批量删除【请填写功能名称】
     *
     * @param ids 需要删除的【请填写功能名称】主键
     * @return 结果
     */
    @Override
    public int deleteEmployeeByIds(Long[] ids) {
        return employeeMapper.deleteEmployeeByIds(ids);
    }

    /**
     * 删除【请填写功能名称】信息
     *
     * @param id 【请填写功能名称】主键
     * @return 结果
     */
    @Override
    public int deleteEmployeeById(Long id) {
        return employeeMapper.deleteEmployeeById(id);
    }


    @Autowired
    private WxLoginService wxLoginService;


    @Override
    public WxUserDto employeeRegister(WxLoginVo wxLoginVo) {

        String secondCode = wxLoginVo.getSecondCode();

        String accessToken = wxLoginService.getAccessToken(wxLoginVo.getPlatform());

        String phoneNumber = wxLoginService.getPhoneNumber(secondCode, accessToken);

        String openId = wxLoginVo.getOpenId();

        if (Objects.nonNull(openId)) {
            redisTemplate.opsForHash().put(String.format(USER_USER_PREFIX, wxLoginVo.getPlatform()), openId, phoneNumber);
        }

        return WxUserDto.builder().phone(phoneNumber).build();
    }

    @Override
    public Employee doRegister(RoleRegisterVo roleRegisterVo) {

        EmployeeVo employeeVo = roleRegisterVo.getBasicInfo();

        Employee newEmployee = new Employee();

        BeanUtil.copyProperties(employeeVo, newEmployee);

        String employeeNo = AutoCreateNumberUtil.generateNo("", 10);

        newEmployee.setEmployeeNo(employeeNo);

        newEmployee.setPhone(roleRegisterVo.getPhone());

        newEmployee.setGrzcsj(new Date());

        newEmployee.setTel(Long.parseLong(roleRegisterVo.getPhone()));

        List<Employee> employees = employeeMapper.selectEmployeeList(newEmployee);
        // todo 后续改成insertOrUpdate
        if (employees.isEmpty()) {
            employeeMapper.insertEmployee(newEmployee);
            return newEmployee;
        }
        return employees.get(0);
    }

    @Override
    public void workInfoSubmit(RoleRegisterVo roleRegisterVo) {
        EmployeeVo employeeVo = new EmployeeVo();
        Assert.notNull(roleRegisterVo.getPhone(), "手机号不能为空");
        employeeVo.setPhone(roleRegisterVo.getPhone());
        List<Employee> employees = employeeMapper.selectEmployeeList(employeeVo);
        if (employees.isEmpty()) {
            throw new RuntimeException("工作信息提交失败,您未注册，请到个人中心我的信息注册个人信息");
        }
        Employee employee = employees.get(0);
        EmployeeRoleReleation employeeRoleReleation = new EmployeeRoleReleation();
        RoleDetail roleDetail = roleRegisterVo.getRoleDetail();
        if (Objects.nonNull(roleDetail.getHg())) {
            employeeRoleReleation.setEmployeeType(EmployeeTypeEnum.hg.name());
            RoleDetail.Hg hg = roleDetail.getHg();
            hg.setJddzcode(employee.getJddzcode());
        }
        if (Objects.nonNull(roleDetail.getBj())) {
            employeeRoleReleation.setEmployeeType(EmployeeTypeEnum.bj.name());
            RoleDetail.Bj bj = roleDetail.getBj();
            bj.setJddzcode(employee.getJddzcode());
        }
        employeeRoleReleation.setRoleDetail(JSONUtil.toJsonStr(roleDetail));
        employeeRoleReleation.setEmployeeNo(employee.getEmployeeNo());
        employeeRoleReleation.setCreateTime(new Date());
        employeeRoleReleationMapper.insertEmployeeRoleReleation(employeeRoleReleation);
    }

    private static Map<String, EmployeeDto> ALL_EMPLOYEE = new ConcurrentHashMap<>();

    public static Map<String, EmployeeDto> getAllEmployee() {
        return ALL_EMPLOYEE;
    }

    public EmployeeDto getAllEmployeeByNo(String emplyeeNo) {
        if (ALL_EMPLOYEE.isEmpty()) {
            ALL_EMPLOYEE = queryAllEmployeeToMap();
            if (Objects.nonNull(ALL_EMPLOYEE)) {
                return ALL_EMPLOYEE.get(emplyeeNo);
            }
            return null;
        }
        return ALL_EMPLOYEE.get(emplyeeNo);
    }

    AtomicBoolean atomicBoolean = new AtomicBoolean();

    @Override
    public List<EmployeeAndReleationDto> getEmployeeListByQueryType(EmployQueryVo employQueryVo) {
        boolean load = atomicBoolean.compareAndSet(false, true);
        if (load) {
            Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
                try {
                    Map<String, EmployeeDto> employeeDtoMap = queryAllEmployeeToMap();
                    if (Objects.nonNull(employeeDtoMap)) {
                        ALL_EMPLOYEE = employeeDtoMap;
                    }
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }, 0, 3, TimeUnit.SECONDS);
        }

        Map<String, EmployeeDto> allEmployee = getAllEmployee();

        if (allEmployee.isEmpty()) {
            PageHelper.startPage(employQueryVo.getPageNum(), employQueryVo.getPageSize());
            List<EmployeeDto> employeeRoleReleations = employeeRoleReleationMapper.queryEmployeeAndReleationAll();
            List<EmployeeAndReleationDto> employeeAndReleationDtoList = getEmployeeAndReleationDtos(employQueryVo, employeeRoleReleations);
            return employeeAndReleationDtoList;
        }
        Map<String, EmployeeDto> allEmployeePage = pageEmployee(employQueryVo, allEmployee);
        List<EmployeeAndReleationDto> employeeAndReleationDtoList = getEmployeeAndReleationDtos(employQueryVo, allEmployeePage);
        return employeeAndReleationDtoList;
    }

    private static Map<String, EmployeeDto> pageEmployee(EmployQueryVo employQueryVo, Map<String, EmployeeDto> allEmployee) {
        Map<String, EmployeeDto> allEmployeePage = new HashMap<>();

        Set<Map.Entry<String, EmployeeDto>> entries = allEmployee.entrySet();

        int i = 0;
        int start = (employQueryVo.getPageNum() - 1) * employQueryVo.getPageSize();
        int end = start + employQueryVo.getPageSize();
        for (Map.Entry<String, EmployeeDto> entry : entries) {
            i++;
            if (i > start) {
                if (i <= end) {
                    allEmployeePage.put(entry.getKey(), entry.getValue());
                    continue;
                }
                break;
            }
        }
        return allEmployeePage;
    }

    private Map<String, EmployeeDto> queryAllEmployeeToMap() {
        List<EmployeeDto> employeeRoleReleations = employeeRoleReleationMapper.queryEmployeeAndReleationAll();
        Map<String, EmployeeDto> employeeDtoMap = employeeRoleReleations.stream().collect(Collectors.toMap(EmployeeDto::getEmployeeNo, employeeDto -> employeeDto));
        return employeeDtoMap;
    }

    private List<EmployeeAndReleationDto> getEmployeeAndReleationDtos(EmployQueryVo employQueryVo, Collection<EmployeeDto> employeeRoleReleations) {
        List<EmployeeAndReleationDto> employeeAndReleationDtoList = new ArrayList<>();
        for (EmployeeDto employeeDto : employeeRoleReleations) {
            EmployeeAndReleationDto employeeAndReleationDto = parseEmployee(employQueryVo.getPlatform(), employQueryVo.getJddzcode(), employeeDto);
            if (Objects.nonNull(employeeAndReleationDto)) {
                employeeAndReleationDtoList.add(employeeAndReleationDto);
            }
        }
        return employeeAndReleationDtoList;
    }

    private List<EmployeeAndReleationDto> getEmployeeAndReleationDtos(EmployQueryVo employQueryVo, Map<String, EmployeeDto> employeeRoleReleations) {
        List<EmployeeAndReleationDto> employeeAndReleationDtoList = new ArrayList<>();
        employeeRoleReleations.forEach((k, v) -> {
            EmployeeAndReleationDto employeeAndReleationDto = parseEmployee(employQueryVo.getPlatform(), employQueryVo.getJddzcode(), v);
            if (Objects.nonNull(employeeAndReleationDto)) {
                employeeAndReleationDtoList.add(employeeAndReleationDto);
            }
        });
        return employeeAndReleationDtoList;
    }

    public EmployeeAndReleationDto parseEmployee(String platform, String jddzCode, EmployeeDto employeeDto) {
        return parseEmployee(platform, jddzCode, employeeDto, true);
    }

    public EmployeeAndReleationDto parseEmployee(String platform, String jddzCode, EmployeeDto employeeDto, boolean replace) {
        JSONObject roleDeatil = JSONUtil.parseObj(employeeDto.getRoleDetail());
        JSONObject o = (JSONObject) roleDeatil.get(platform);
        if (Objects.isNull(o)) {
            return null;
        }

        parseDictValue(platform, o);

        Object jddzcode = roleDeatil.get(JDDZCODE);

        if (replace) {
            employeeDto.setXb(dictCacheManager.getDictByCode(employeeDto.getXb()));
            employeeDto.setRoleDetail(null);
        }

        if (Objects.nonNull(jddzcode) && !jddzcode.toString().equals(jddzCode)) {
            return null;
        } else {
            return EmployeeAndReleationDto.builder().employeeRelation(roleDeatil).employee(employeeDto).build();
        }
    }

    private static void parseDictValue(String platform, JSONObject o) {
        Map<String, Integer> map = EMPLOYEE_DICT.get(platform);
        Iterator<Map.Entry<String, Object>> iterator = o.iterator();

        while (iterator.hasNext()) {
            Map.Entry<String, Object> next = iterator.next();
            if (Objects.nonNull(map.get(next.getKey()))) {
                List<Map<String, String>> dictList = new ArrayList<>();
                String dictValue = next.getValue().toString();
                String[] split = dictValue.split(",");
                for (String dict : split) {
                    Map<String, String> dictKeyValue = new HashMap<>();
                    dictKeyValue.put(label, DICT_CACHE.get(Long.parseLong(dict)));
                    dictKeyValue.put(value, dict);
                    dictList.add(dictKeyValue);
                }
                o.set(next.getKey(), dictList);
            }
        }
    }

    @Override
    public WxUserDto employeeLogin(WxLoginVo wxLoginVo) {

        String openId = commonOpenApiService.queryOpenId(wxLoginVo);

        Object phone = redisTemplate.opsForHash().get(String.format(USER_USER_PREFIX, wxLoginVo.getPlatform()), openId);

        if (Objects.nonNull(phone)) {
            return WxUserDto.builder().userType(commonOpenApiService.queryUserWorkType(openId)).openId(openId).phone(phone.toString()).build();
        }

        String phoneNumber = commonOpenApiService.getPhoneNumber(wxLoginVo);

        redisTemplate.opsForHash().put(String.format(USER_USER_PREFIX, wxLoginVo.getPlatform()), openId, phoneNumber);

        return WxUserDto.builder().userType(commonOpenApiService.queryUserWorkType(openId)).openId(openId).phone(phoneNumber).build();
    }

    @Override
    public String updateEmployeeInfo(EmployeeVo employeeVo) {
        try {
            Employee employee = new Employee();
            BeanUtil.copyProperties(employeeVo, employee);
            employee.setUpdateTime(new Date());
            int updateCount = employeeMapper.updateEmployee(employee);
            if (updateCount > 0) {
                return "修改成功";
            }
        } catch (Exception exception) {
            log.error("更新员工信息失败 employeeNo {} ", employeeVo.getEmployeeNo(), exception);
            throw new RuntimeException("修改失败 原因=> " + exception.getCause());
        }
        throw new RuntimeException("修改失败");
    }

    @Override
    public EmployeeAndReleationDto queryEmployeeInfo(EmployeeVo employeeVo) {
        String employeeNo = employeeVo.getEmployeeNo();
        Assert.notNull(employeeNo, "员工编号不能为空");
        EmployeeDto employeeDto = employeeMapper.selectEmployeeAndReleationByNo(employeeNo);
        if (Objects.isNull(employeeDto)) {
            throw new RuntimeException("未查询到员工信息");
        }
        String roleDetail = employeeDto.getRoleDetail();

        JSONObject jsonObject = JSONUtil.parseObj(roleDetail);

        employeeDto.setRoleDetail(null);

        return EmployeeAndReleationDto.builder().employee(employeeDto).employeeRelation(jsonObject).build();
    }

    @Override
    public String updateWorkInfo(RoleRegisterVo roleRegisterVo) {
        Assert.notNull(roleRegisterVo.getBasicInfo().getEmployeeNo(), "员工编号不能为空");
        EmployeeRoleReleation employeeRoleReleation = employeeRoleReleationMapper.selectEmployeeRoleReleationByEmployeeNo(roleRegisterVo.getBasicInfo().getEmployeeNo());
        Assert.notNull(employeeRoleReleation, "未查询到角色信息");
        String roleDetail = employeeRoleReleation.getRoleDetail();
        JSONObject jsonObject = JSONUtil.parseObj(roleDetail);
        Object o = JSONUtil.parseObj(roleRegisterVo.getRoleDetail()).get(roleRegisterVo.getPlatform());
        jsonObject.put(roleRegisterVo.getPlatform(), o);
        employeeRoleReleation.setRoleDetail(JSONUtil.toJsonStr(jsonObject));
        int i = employeeRoleReleationMapper.updateEmployeeRoleReleation(employeeRoleReleation);
        if (i > 0) {
            return "修改成功";
        }
        throw new RuntimeException("修改失败");
    }

}
